/***************************************************************************
 *   mgpi_gpu_calc.c - Mathematical Calulations using GPU Test	           *
 *   Copyright (C) 2008 by cmaster.matso                                   *
 *   cmaster.matso@gmail.com                                               *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include <MGPI/mgpi.h>

/* Code for the NVidia GeForce 8400M GS graphic card - compiled & tested on Linux platform */

/**
 * Program entry point.
 */
int main(int argc, char *argv[]) {
    int size = 4; /* should be a power of 2 */
    float *input = (float *) malloc(size * size * sizeof (float));
    float *output = (float *) malloc(size * size * sizeof (float));
    const char *routine_code;

    int i, name;

    MGPI_GPUstream *gpustreams;
    MGPI_GPUparam *gpuparam;

    MGPI_CollectGarbage(input);
    MGPI_CollectGarbage(output);

    for (i = 0; i < size * size; ++i) {
        if (i >= 5) input[i] = 0.8f;
        else input[i] = 0.0f;
        output[i] = 0.;
    }

    fprintf(stdout, "Starting values in the float arrays:\n");
    fprintf(stdout, "input: output:\n");
    for (i = 0; i < size * size; ++i) fprintf(stdout, "%2.2f, %2.2f\n", input[i], output[i]);

    /* Init MGPI */
    MGPI_Init();

    atexit(MGPI_Exit);

    /* Start the GPU calculations system */
    MGPI_BeginVectorComputations(MGPI_GPU_VECTOR_CALC, &argc, argv);

    /* Allocate two GPU streams - one for input data, one for the outcome */
    gpustreams = (MGPI_GPUstream *) MGPI_AllocGPUStreamsNV32(2, size, GL_FLOAT);

    /* Write the input array into the GPU stream */
    if (!MGPI_WriteGPUStreamNV(input, &gpustreams[0])) {
        MGPI_PostMessagef("main: an error occured during the GPU stream write");
        exit(EXIT_FAILURE);
    }

    /* Note that the stream allocation and write are GPU hardware dependent */

    /* Allocate GPU parameter for the GPU routine call and pass streams to it */
    gpuparam = MGPI_AllocGPUParam(gpustreams, 0, 2);

    /* Load fragment shader code for the GPU routine */
    routine_code = (const char *) fload("fir_filter.frag");

    /* Pass the code to the system */
    MGPI_SetGPURoutineCode(NULL, routine_code);

    /* Register GPU routine */
    name = MGPI_RegGPURoutine(gpuparam);

    /* Setup GPU parameter */
    MGPI_SetupGPUParam(gpuparam);

    /* Pass uniform variables for the routine */
    MGPI_SetGPUVariable(MGPI_GLSL_FLOAT4, "filter_params", 1.0f, 1.0f, 1.0f, 1.0f);
    MGPI_SetGPUVariable(MGPI_GLSL_FLOAT1, "signal_fragment_length", (float) size);

    /* Now call the GPU routine */
    MGPI_CallRoutine(name);

    /* Free the registered routine */
    MGPI_FreeGPURoutine(name);

    /* Read the output array from the GPU stream */
    if (!MGPI_ReadGPUStream(output, gpustreams)) {
        MGPI_PostMessagef("main: an error occured during the GPU stream read");
        exit(EXIT_FAILURE);
    }

    fprintf(stdout, "Final values of the float arrays:\n");
    fprintf(stdout, "input: output:\n");
    for (i = 0; i < size * size; ++i) fprintf(stdout, "%2.2f, %2.2f\n", input[i], output[i]);

    /* Turn off the system */
    MGPI_EndVectorComputations();
    MGPI_FreeComputKernel();
    MGPI_FreeGPUParam(gpuparam);
    free((char *) routine_code);

    return EXIT_SUCCESS;
}

